<template>
  <div class="menu-tree-box">
    <!--    <div class="clearfix menu-header-box" @click="handleClickTitle">-->
    <!--      <div class="menu-header-left fl">-->
    <!--        <div class="menu-title-line"></div>-->
    <!--        <span class="menu-title" :class="treeClickNode ?'':'menu-title-active'">{{-->
    <!--            title-->
    <!--          }}</span>-->
    <!--      </div>-->
    <!--      <el-button class="fr" icon="el-icon-plus" size="mini" @click.stop="handleAddNode()"></el-button>-->
    <!--    </div>-->
    <slot name="header"></slot>
    <div class="menu-tree-search-box">
      <el-input class="search-input" placeholder="请输入目录名称" v-model="filterText" @change="handleSearch">
        <template #suffix>
          <i style="cursor: pointer;" class="el-icon-search" @click="handleSearch"></i>
        </template>
      </el-input>
    </div>

    <el-tree
      ref="tree"
      :data="data"
      :props="defaultProps"
      node-key="baseId"
      :default-expand-all="true"
      @node-contextmenu="openTreeMenu"
      @node-drop="handleDrop"
      :draggable="false"
      :filter-node-method="filterNode"
    >
      <div
        v-if="treeRightClickNode == node && nodeEditable"
        slot-scope="{ node, data }"
        class="flex" style="align-items: center;">
        <img v-if="iconic" class="node-custom-icon mr5" :src="iconSrc(data)">
        <el-input
          ref="nodeInput"
          class="node-input"
          v-model="data[options.label]"
          @blur="handleNodeBlur(node)"
          @click.native.stop="handleNodeClick(node,data)"
        >
        </el-input>
      </div>
      <div
        v-else
        class="node-custom flex"
        :class="treeClickNode && treeClickNode.id == node.id ? 'node-active':''"
        slot-scope="{ node, data }"
        @click.stop="handleNodeClick(node,data)"
        @dblclick="handleNodeDbClick(node,data)"
        @mouseenter="handleMouseEnter($event,data)"
        @mouseleave="handleMouseLeave($event,data)"
      >
        <img v-if="iconic" class="node-custom-icon mr5" :src="iconSrc(data)">
        <span class="textoverflow node-label">{{ data[options.label] }}</span>
        <template v-if="!readable(data)">
          <div v-if="data.baseId == '0'" class="clearfix node-action flex">
            <i class="i-add mr10" @click.stop.prevent="handleAddNode(node)"></i>
          </div>
          <div v-else class="clearfix node-action flex">
            <i class="i-edit mr5" @click.stop.prevent="handleEditNode(node)"></i>
            <i class="i-add mr5" @click.stop.prevent="handleAddNode(node)"></i>
            <i class="i-del mr10" @click.stop.prevent="handleRemoveNode(node)"></i>
          </div>
        </template>

      </div>
    </el-tree>

    <div v-show="showTreeMenu" class="treeMenu">
      <div @click="handleAddNode(treeRightClickNode)">添加</div>
      <div @click="handleEditNode">修改</div>
      <div @click="handleRemoveNode">删除</div>
    </div>
    <el-dialog
      title="添加目录"
      :visible.sync="nodeVisible"
      :show-close="false"
      width="30%"
    >
      <el-form ref="menuForm" :model="nodeForm" :rules="nodeRules" label-width="auto">
        <el-form-item label="名称" prop="catalogName">
          <el-input v-model="nodeForm.catalogName"></el-input>
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="nodeVisible = false">取消</el-button>
        <el-button type="primary" @click="submitNode">确定</el-button>
      </span>
    </el-dialog>

  </div>
</template>

<script>

import request, {DataUrl} from '@/utils/request'

export default {
  name: 'MenuTree',
  props: {
    options: {
      type: Object,
      default: () => {
        return {
          label: 'catalogName',
          icon: 'iconName'
        }
      }
    },
    name: {
      type: String,
      default: ''
    },
    title: {
      type: String,
      default: '目录'
    },
    addUrl: {
      type: String,
      default: ''
    },
    delUrl: {
      type: String,
      default: ''
    },
    queryUrl: {
      type: String,
      default: ''
    },
    adjustUrl: {
      type: String,
      default: ''
    },
    params: {
      type: Object,
      default: () => {
        return {}
      }
    },
    rightClicking: {
      //可右击
      type: Boolean,
      default: false
    },
    doubleClicking: {
      //可双击
      type: Boolean,
      default: false
    },
    onlyReadable: {
      //只读,隐藏添加删除编辑按钮
      type: Boolean,
      default: false
    },
    iconic: {
      type: Boolean,
      default: false
    },
    iconName: {
      type: String,
      default: ''
    },
    iconOptions: {
      type: Object,
      default: () => {
        return {
          menu: '',
          item: ''
        }
      }
    },
    rootId:{
      type: String,
      default: '0'
    }
  },
  data() {
    return {
      filterText: '',
      data: [],
      defaultProps: {
        children: 'childrenList',
        label: this.options.label,
        isLeaf: (data, node) => {
          return !data.childrenList || data.childrenList.length == 0
        }
      },
      showTreeMenu: false,// 是否显示修改删除菜单
      treeRightClickNode: null,// 当前右击的节点
      treeClickNode: null, // 当前点击选中的节点
      nodeEditable: false,// 是否正处于编辑状态
      timer: null, //计时器双击、单击事件
      nodeVisible: false,
      nodeForm: {
        parentId: '',
        [this.options.label]: '',
        ancestors: ''
      },
      nodeRules: {
        catalogName: [
          {required: true, message: '请输入名称', trigger: 'blur'}
        ]
      },
      posMapper: {
        before: '0',
        after: '1',
        inner: '2'
      },
      expandedIds: [] //记录展开的节点，拖拽移动后回显使用
    }
  },
  computed: {},
  mounted() {
    this.loadTree()
  },
  watch:{
    params: {
      handler(val) {
        this.loadTree()
      },
      deep:true
    }
  },
  methods: {
    iconSrc(item) {
      if (item.isCheck == '1') {
        if (item.scriptType == 'shell') {
          return require('@/assets/icons/menu/sh.png')
        }

        if (item.scriptType == 'sql') {
          return require('@/assets/icons/menu/sql.png')
        }

        if(this.iconName) {
          return require(`@/assets/icons/menu/${this.iconName}`)
        }

        return require('@/assets/icons/menu/sh.png')
      }

      // if(item[this.options.icon]) {
      //   return require(`@/assets/icons/menu/${item[this.options.icon]}.png`)
      // }
      if (item.isHovered) {
        return require('@/assets/icons/menu/folder2.png')
      }
      return require('@/assets/icons/menu/folder.png')

    },
    handleMouseEnter(e, item) {
      this.$set(item, 'isHovered', true)
    },
    handleMouseLeave(e, item) {
      this.$set(item, 'isHovered', false)
    },
    refreshData() {
      this.loadTree()
    },
    readable(data) {
      if (this.onlyReadable) return true
      return data.isCheck == '1'
    },
    handleSearch() {
      this.$refs.tree.filter(this.filterText)
    },
    filterNode(value, data) {
      if (!value) return true
      return data[this.options.label].indexOf(value) !== -1
    },
    handleClickTitle() {
      this.handleNodeClick(null, {baseId: ''})
    },
    // 加载目录树
    queryCatalog() {
      return request({
        url: DataUrl() + this.queryUrl,
        method: 'GET',
        params:this.params
      })
    },
    // 添加目录节点
    addCatalog(data) {
      return request({
        url: DataUrl() + this.addUrl,
        method: 'POST',
        data
      })
    },
    // 删除目录节点
    delCatalog(id) {
      return request({
        url: DataUrl() + `${this.delUrl}/${id}`,
        method: 'DELETE'
      })
    },
    // 调整目录结构
    adjustPosition(data) {
      return request({
        url: DataUrl() + this.adjustUrl,
        method: 'POST',
        data
      })
    },
    // 加载目录树
    loadTree() {
      this.queryCatalog().then(res => {
        this.data = [{baseId: this.rootId, [this.options.label]: '全部目录', childrenList: res.obj || []}]
        // 回显展开节点
        this.$nextTick(() => {
          let allNodes = this.getAllNodes(this.$refs.tree.store.root.childNodes)
          allNodes.forEach(item => {
            if (this.expandedIds.includes(item.data.baseId)) {
              item.expanded = true
            }
          })
        })
      })
    },
    // 添加节点
    handleAddNode(node) {
      // 记录展开的节点，回显时使用
      this.getExpandedIds()

      this.nodeForm = {
        parentId: '0',
        [this.options.label]: '',
        ancestors: '0'
      }
      if (node) {
        // 添加子节点
        this.nodeForm.parentId = node.data.baseId
        if(node.data.ancestors) {
          this.nodeForm.ancestors = node.data.ancestors + ',' + node.data.baseId
        } else  {
          this.nodeForm.ancestors = node.data.baseId
        }

      }
      this.nodeVisible = true
      if (node) {
        // 添加子节点
        this.closeTreeMenu()
      }
    },
    // 删除节点
    handleRemoveNode(node = this.treeRightClickNode) {
      this.$modal.confirm('是否确认删除？').then(() => {
        // 记录展开的节点，回显时使用
        this.getExpandedIds()
        this.delCatalog(node.data.baseId).then(res => {
          this.$modal.msgSuccess('删除成功')
          this.$eventBus.$emit('menuTreeChange', this.name)
          this.$refs.tree.remove(node)
          if (this.treeClickNode == node) {
            this.treeClickNode = null
          }
          this.treeRightClickNode = null
          this.closeTreeMenu()
          this.loadTree()
        })
      })
    },
    // 修改节点
    handleEditNode(node) {
      // 记录展开的节点，回显时使用
      this.getExpandedIds()
      if (node) {
        this.treeRightClickNode = node
      }
      this.closeTreeMenu()
      this.nodeEditable = true
      this.$nextTick(() => {
        this.$refs.nodeInput.focus()
      })
    },
    // 选择节点、左键单击
    handleNodeClick(node, data) {
      this.treeClickNode = node
      if (this.nodeEditable) return false
      clearTimeout(this.timer) //清除未执行的定时器
      this.timer = setTimeout(() => {
        // node.expanded = !node.expanded
        this.$emit('nodeClick', node, data)
      }, 100)
    },
    // 双击节点编辑
    handleNodeDbClick(node, data) {
      if (!this.doubleClicking) return
      clearTimeout(this.timer) //清除未执行的定时器
      this.treeRightClickNode = node
      this.handleEditNode(node)
    },
    // 鼠标右键点击
    openTreeMenu(event, data, node, target) {
      if (!this.rightClicking) return
      this.showTreeMenu = true // 显示菜单
      this.treeRightClickNode = node // 存储数据
      this.nodeEditable = false
      document.querySelector('.treeMenu').setAttribute('style', `top:${event.clientY}px;left:${event.clientX}px;`)
      document.addEventListener('click', this.closeTreeMenu)
      document.addEventListener('contextmenu', this.closeTreeMenu)
    },
    // 拖拽
    handleDrop(draggingNode, dropNode, dropType, ev) {
      // 记录展开的节点，回显时使用
      this.getExpandedIds()

      // 发送移动目录请求
      let data = {baseId: draggingNode.data.baseId, posId: dropNode.data.baseId, posType: this.posMapper[dropType]}
      this.adjustPosition(data).then(res => {
        if (res.code == 0) {
          // 刷新目录
          this.$eventBus.$emit('menuTreeChange', this.name)
          this.loadTree()
        }
      })
    },
    //递归所有节点的信息
    getAllNodes(nodes = [], arr = []) {
      for (let item of nodes) {
        arr.push(item)
        let parentArr = []
        if (item.childNodes) parentArr.push(...item.childNodes)
        if (parentArr && parentArr.length) this.getAllNodes(parentArr, arr)
      }
      return arr
    },
    // 所有展开的节点
    getExpandedIds() {
      let allNodes = this.getAllNodes(this.$refs.tree.store.root.childNodes)
      let expandedNodes = allNodes.filter(item => {
        return item.expanded
      })
      this.expandedIds = expandedNodes.map(item => {
        return item.data.baseId
      })
    },
    // 失去焦点，提交编辑信息
    handleNodeBlur(node = this.treeRightClickNode) {
      let {baseId, catalogName, parentId} = node.data
      this.addCatalog({baseId, catalogName, parentId}).then(res => {
        this.$modal.msgSuccess('修改成功')
        this.$eventBus.$emit('menuTreeChange', this.name)
        this.treeRightClickNode = null
        this.nodeEditable = false
        this.loadTree()
      })
    },
    // 关闭右键菜单
    closeTreeMenu() {
      this.showTreeMenu = false // 关闭菜单
      document.removeEventListener('click', this.closeTreeMenu)
      document.removeEventListener('contextmenu', this.closeTreeMenu)
    },
    // 提交保存
    submitNode() {
      this.$refs.menuForm.validate((valid) => {
        if (valid) {
          let item = _.cloneDeep(this.nodeForm)
          this.addCatalog(this.nodeForm).then(res => {
            this.$modal.msgSuccess('添加成功')
            this.$eventBus.$emit('menuTreeChange', this.name)
            this.loadTree()
            this.nodeVisible = false
          })
        }
      })
    }
  }
}
</script>

<style scoped lang="scss">

.menu-tree-box {

  .menu-tree-search-box {
    padding: 10px;

    ::v-deep .el-input__suffix {
      color: #3184FF;
    }

    ::v-deep .el-input--medium .el-input__inner {
      height: 36px !important;
      line-height: 36px !important;
      font-size: 14px !important;
    }

    ::v-deep .el-input--medium .el-input__icon {
      line-height: 36px !important;
      display: none;
    }
  }

  .menu-header-box {
    padding: 10px;
    cursor: pointer;

    &:hover {
      background-color: #3184FF;

      .menu-title-line {
        background-color: #FFFFFF !important;
      }

      .menu-title {
        color: #FFFFFF !important;
      }
    }
  }

  .menu-header-left {
    display: flex;
    align-items: center;

    .menu-title-line {
      display: inline-block;
      width: 4px;
      height: 16px;
      background-color: #3184FF;
      border-radius: 2px;
    }

    .menu-title {
      margin-left: 10px;
      font-size: 16px;
      font-weight: bold;
      color: #333333;
    }

    .menu-title-active {
      color: #3184FF !important;
    }
  }


  ::v-deep .el-tree {
    background-color: transparent !important;
  }

  ::v-deep .el-tree-node__content {
    height: 32px;
  }

  .treeMenu {
    position: fixed;
    z-index: 99999;
    top: 50%;
    left: 50%;
    background-color: transparent;
    overflow: hidden;
    //border-radius: 5px;
    border: 1px solid #e6ebf5;
    box-shadow: 0 2px 12px 0 rgb(0 0 0 / 10%);

    div {
      padding: 3px 20px;
      box-sizing: border-box;
      //width: 50px;
      text-align: center;
    }

    div:hover {
      background-color: #eee;
      cursor: pointer;
    }
  }

  .node-input {
    padding: 0;
    width: 100%;
    height: 36px;
    line-height: 36px;

    ::v-deep .el-input__inner {
      height: 36px;
      line-height: 36px;
      color: #3184FF;
      border: none;
      background-color: transparent;
      padding: 0;
    }
  }

  .node-custom-icon {
    width: 14px;
    height: 14px;
  }

  .node-custom {
    width: 100%;
    height: 36px;
    line-height: 36px;
    box-sizing: border-box;
    font-size: 14px;
    font-family: Microsoft YaHei-Regular, Microsoft YaHei;
    font-weight: 400;
    color: #333333;
    display: flex;
    align-items: center;
    justify-content: space-between;

    .node-action {
      visibility: hidden;
      cursor: pointer;
    }

    i {
      display: inline-block;
      width: 17px;
      height: 17px;
      cursor: pointer;
    }

    .i-edit {
      width: 17px;
      height: 17px;
      background-image: url(~@/assets/images/menu-edit.png);
      background-size: 100% 100%;
    }

    .i-add {
      width: 15px;
      height: 15px;
      background-image: url(~@/assets/images/menu-add.png);
      background-size: 100% 100%;
    }

    .i-del {
      width: 15px;
      height: 15px;
      background-image: url(~@/assets/images/menu-del.png);
      background-size: 100% 100%;
    }

  }

  .node-active {
    color: #3184FF;
  }

  ::v-deep .el-tree-node__content {
    &:hover {
      background-color: #3184FF;
      color: #FFFFFF;

      .node-label {
        flex: 1;
        width: 0;
      }

      .node-custom {
        color: #FFFFFF;
      }

      .node-action {
        visibility: visible;
      }

      .el-input__inner {
        color: #FFFFFF;
      }

    }

    .node-label {
      display: inline-block;
      width: 100%
    }

    .node-action {
      align-items: center;
      justify-content: end;
      width: 70px;
    }

  }
}

</style>


<style scoped lang="scss">

.menu-tree-box {

  .search-input {
    ::v-deep .el-input__suffix-inner {
      position: absolute;
      right: 50%;
      top: 50%;
      transform: translate(-50%, -50%);
    }
  }

  ::v-deep .el-tree-node__content > .el-tree-node__expand-icon {
    color: #999999 !important;
  }

  ::v-deep .is-leaf::before {
    display: none;
  }

  //::v-deep .el-tree-node__expand-icon.expanded {
  //  -webkit-transform: rotate(0deg);
  //  transform: rotate(0deg);
  //}
  //
  //// 没有展开且有子节点
  //::v-deep .el-icon-caret-right:before {
  //  background: url("~@/assets/images/icon-menu-add.png") no-repeat 0 0;
  //  content: '';
  //  display: block;
  //  width: 17px;
  //  height: 17px;
  //  font-size: 16px;
  //  background-size: 16px;
  //}
  //
  //// 已经展开且有子节点
  //::v-deep .el-tree-node__expand-icon.expanded.el-icon-caret-right:before {
  //  background: url("~@/assets/images/icon-menu-del.png") no-repeat 0 0;
  //  content: '';
  //  display: block;
  //  width: 17px;
  //  height: 17px;
  //  font-size: 16px;
  //  background-size: 16px;
  //}
  //
  //// 没有子节点
  //::v-deep .el-tree-node__expand-icon.is-leaf::before {
  //  //background: url("~@/assets/images/icon-menu-del.png") no-repeat 0 3px;
  //  background: none;
  //  content: '';
  //  display: block;
  //  width: 0;
  //  height: 0;
  //  font-size: 16px;
  //  background-size: 16px;
  //}

  // 选中行高亮显示
  ::v-deep .el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content {
    //color: $moaMainColor;
  }

  // 文字长度超出容器宽度换行显示
  ::v-deep .el-tree-node__content {
    height: auto;
    line-height: 28px;

    .el-tree-node__label {
      white-space: break-spaces !important;
    }
  }

}

</style>
